
#ifndef ROPUFU_MORE_MATH_HPP_INCLUDED
#define ROPUFU_MORE_MATH_HPP_INCLUDED

#include <aftermath/template_math.hpp>

#include <algorithm>
#include <array>
#include <cstdint>

namespace ropufu
{
    template <std::size_t t_power>
    struct npow_double
    {
        static constexpr double value(double base)
        {
            return base * npow_double<t_power - 1>::value(base);
        }
    };

    template <>
    struct npow_double<0>
    {
        static constexpr double value(double)
        {
            return 1.0;
        }
    };

    template <typename t_test_type, typename t_replacement_type>
    struct switch_void
    {
        typedef t_test_type type;
    };

    template <typename t_replacement_type>
    struct switch_void<void, t_replacement_type>
    {
        typedef t_replacement_type type;
    };

    template <std::size_t t_count_streams, std::size_t t_count_affected>
    struct choose_at_most
    {
        static const std::size_t value =
            aftermath::nchoosek<t_count_streams, t_count_affected>::value +
            choose_at_most<t_count_streams, t_count_affected - 1>::value;
    };

    template <std::size_t t_count_streams>
    struct choose_at_most<t_count_streams, 1>
    {
        static const std::size_t value = aftermath::nchoosek<t_count_streams, 1>::value;
    };

    template <std::size_t t_count_streams>
    struct choose_at_most<t_count_streams, 0>
    {
        static const std::size_t value = aftermath::nchoosek<t_count_streams, 0>::value;
    };

    struct more_math
    {
        template <std::size_t K, typename T>
        static void top_sort(std::array<T, K>& value, std::size_t n_top)
        {
            if (K == n_top) return;
            std::sort(value.begin(), value.end());
        }

        std::size_t n_choose_k(std::size_t n, std::size_t k)
        {
            if (n == 0 || k == 0 || n == k) return 1;

            std::size_t num = 1;
            std::size_t denom = 1;
            for (std::size_t j = 0; j < k; j++)
            {
                num *= (n - j);
                denom *= (j + 1);
            }
            return num / denom;
        }
    };
}

#endif // ROPUFU_MORE_MATH_HPP_INCLUDED
